feat(plugin-kanban,plugin-calendar): declare the seven scalar spec keys both renderers already honour (#8201, slice 1 of 2) - #8309
Merged
os-justin merged 1 commit intoSep 7, 2026
Conversation
…ys both renderers already honour `ComponentPropsMap` declares 13 top-level keys for `object-kanban` and 9 for `object-calendar`; the registrations published 4 of each. The gap was structural rather than considered — the console registers both blocks with `registerLazy` and `getConfig` is loaded-only, so they sat outside the console's reverse-parity population until objectui#8176 loaded it. Declares the seven whose arm is SCALAR and whose read site changes behaviour: `groupBy`, `cardTitle`, `titleField`, `swimlaneField`, `coverImageField` on the board, and `defaultView` (the spec's three-member enum) + `locale` on the calendar. Both tags of each block now spread ONE shared list, so the two published surfaces cannot drift apart by hand-copy. The seven matching `UNPUBLISHED_EXEMPTIONS` entries are deleted in the same change and both halves of the shrink-only backlog ceiling move 15 -> 8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-justin
marked this pull request as ready for review
September 7, 2026 10:14
os-justin
enabled auto-merge
September 7, 2026 10:15
This was referenced Sep 7, 2026
os-justin
deleted the
claude/issue-8201-kanban-calendar-undeclared-spec-keys
branch
September 7, 2026 11:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #8201 — this is slice 1 of 2, so it deliberately does not close the card. See the slice boundary below for what stays open and why.
What this does
Declares seven
ComponentPropsMapkeys that the twoobject-*renderers already read and already act on, and deletes the seven matchingUNPUBLISHED_EXEMPTIONSentries in the same change.object-kanbangroupBystringObjectKanban.tsxmaterializes lanes from the field's picklist options;bucketCardsIntoColumnsbuckets records by its value; a drag between lanes writes the value backobject-kanbancardTitlestringeffectiveDatapicks the card-title field (read ahead oftitleField)object-kanbantitleFieldstringobject-kanbanswimlaneFieldstringeffectiveSchema.swimlaneField, whichKanbanImplsplits the board onobject-kanbancoverImageFieldstringbucketCardsIntoColumnsmaps it onto each card'scoverImage, rendered as the card<img>object-calendardefaultViewenumObjectCalendar.tsxseeds itsviewstate fromschema.defaultViewobject-calendarlocalestringresolveAuthoredLocale(rest.locale)forwards a tagIntlaccepts into the component's date/time formattingBoth tags of each block (
object-kanban/view:kanban,object-calendar/view:calendar) now spread one shared list rather than two hand-copies. The two tags are the same renderer, so a hand-copy was the only way they could ever disagree.No renderer behaviour changes. Every one of these keys was already read; what changes is that the html tier stops reporting working metadata as
unknown-prop(objectui#6678's shape) and authoring tools can discover them.Clause ② — this widens the authoring surface, and here are the grounds
Declaring an input widens what an author may write, so the grounds are stated rather than assumed. They are the same grounds #8186 (
filter) and #8223 (sort) cleared on: the spec already declares the key and the renderer already honours it, so this restoresdeclared = enforcedinstead of publishing anything new.That claim was measured, not assumed, because #8172 is the counter-example:
limitis taught by four faces and refused by name by this same strictComponentPropsMap. Every one of the fifteen keys on the card was probed with a control key on the samesafeParsecall:The control draws
unrecognized_keyson the same call shape while none of the fifteen does — so "the spec declares it" is a verdict here, not a vacuous read. The probe is preserved as row 4 of each new pin test.#8212 landed a tightened direction: every array/object-armed input must pin its member shape, so declaring such a key owes three things — the
inputsentry, the exemption deletion, and aMEMBER_PINSentry whose shape must be measured at the sink rather than assumed.The boundary drawn here is the declared arm, and it was chosen because it is mechanical rather than tasteful:
structuredInputsin the parity gate is keyed off the declared arm, a scalar arm never enters that population, so these seven owe noMEMBER_PINSentry andMEMBER_PIN_EXEMPTION_CEILINGstays at 62. A reviewer can check the boundary instead of agreeing with it.Eight keys stay behind, and the card stays open:
object-kanban.data,.cardFields,.grouping,.conditionalFormatting;object-calendar.data,.staticData). Each needs a member pin measured at its own sink. Note that feat(plugin-calendar): declare thesortinput bothobject-calendarregistrations read #8223's lesson applies here and is not yet resolved for any of them: the twofilterpins assert identity (toBe),sort's does not, becauseconvertSortToQueryParamsbuilds a new map. Assuming the identity shape is the error that had to be corrected on main once already.object-calendar.loading— scalar, but held back for a different reason: it is inert alone.ObjectCalendar.tsxappliesexternalLoadingonly underhasExternalData, so an authoredloadingdoes nothing unlessdatais authored too. It ships withdata, in the slice that measuresdata's member shape.object-kanban.quickAdd— ESCALATED, not deferred. Measured: this renderer does not honour it.KanbanImplgates the control onquickAdd && onQuickAdd(two sites),onQuickAddis an finding(types): 28 zod-mirror keys are declaredz.function(), which NO JSON document can satisfy — 14 in-repo corpus files author them and are silently invalid #6124 runtime slot the zod twin refuses by name, and nothing on theObjectKanbanpath supplies one. That measurement is already tracked as plugin-kanban:quickAddis inert onobject-kanban/kanban—ObjectKanbannever supplies theonQuickAddruntime slot the control is gated on #8285. What remains is a product ruling — permanent carve-out, or a feature gap whose fix makes the key declarable — so its ledger entry is left exactly as it was rather than rewritten into a carve-out reason this PR has no standing to write.Ledger
The backlog ceiling moves 15 → 8, and both assertions carrying it move together (
toBeLessThanOrEqualandtoBe, sameit()); moving onlytoBewould leave the other banking headroom the ratchet exists to refuse. Proven below.Corrected in passing: the prose above that ceiling read "Sixteen … ten on
object-kanban, six onobject-calendar" while both assertions already read 15 — #8223 moved the numbers and not the sentence. A stale count there is what makes a reader distrust the assertions instead of the prose.Evidence
Parity gate assertion count: 198 before, 198 after — no move. Measured by reverting the three tracked files to
origin/mainon this worktree, running, and restoring by state. No move is expected: the gate's rows are staticit()s, and the change moves counts inside arrays those rows read, not the row set.Every new pin proven able to fail — red BY NAME, per registration, restored BY STATE.
Ablate
groupByfrom the kanban list anddefaultViewfrom the calendar list (one line each, on-disk deletion verified bygrep -cFgoing 1 → 0 andgit diff --statshowing the deletions):Per-registration redness, not per-file: each tag reddens on its own named row, and 28 rows stayed green.
Ablate the ledger — re-add one deleted exemption while the declaration stands:
The second row is the proof that both halves of the ceiling moved: it is the
toBeLessThanOrEqualassertion firing.Ablate the honour claim — neutralise the
coverImagemapper inbucketCardsIntoColumns:One row, precisely.
Every restore was verified by state, never by an exit code:
git diff HEADempty, andgit hash-object <path>equal togit rev-parse HEAD:<path>for each mutated file.Suites and gates (all from the repo root —
pnpm --filter PKG exec vitest run FILEis refused here by #3378's guard):apps/console/.../registry-inputs-spec-parity.test.ts@object-ui/plugin-kanbantest@object-ui/plugin-calendartestplugin-kanban+plugin-calendartype-checktsc --noEmitandtsc -p tsconfig.test.json, so the new tests are typechecked)@object-ui/consoletype-checkcheck:control-bytescheck:sdui-registration-pinspnpm --filter @object-ui/console build)check:element-data-source-declarationcheck:designer-field-key-parity·check:handler-key-reads·check:spec-symbols·check:unreferenced-sources·check:side-effects-array·check:self-import·check:phantom-depsRepo-wide
pnpm lintand the full suite are left to CI.Found in passing, filed not fixed
#8308 —
ObjectKanban.tsxresolves thecardTitle/titleFieldpair with||at:403(card list) and??at:1077(detail drawer). An authoredcardTitle: ''therefore titles the cards fromtitleFieldwhile the drawer heading falls through to the record floor: one document, two answers. Not fixed here — this PR declares the two spellings without changing how either resolves — but declaring them makes the divergence more reachable, which is why it is filed.Reviewer note
⛔ Draft on purpose. The PM flips and lands; auto-merge is not enabled.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S
Generated by Claude Code